package errorx

import (
	"context"
	"errors"
	"fmt"
	"nexus/internal/types"
	"strings"

	"github.com/go-sql-driver/mysql"
)

// ErrorX 错误类型定义
type ErrorX struct {
	Code    int
	Message string
}

// NewErrorX 创建错误类型
func NewErrorX(code int, message string) *ErrorX {
	return &ErrorX{
		Code:    code,
		Message: message,
	}
}

// ErrorX 实现 error 接口
func (e *ErrorX) Error() string {
	return e.Message
}

func ErrHandler(ctx context.Context, err error) (int, any) {
	switch err.(type) {
	case *ErrorX:
		var c *ErrorX
		errors.As(err, &c)
		return c.Code, ErrorX{
			Code:    c.Code,
			Message: c.Message,
		}
	default:
		return FailedCode, ErrorX{
			Code:    FailedCode,
			Message: err.Error(),
		}
	}
}

func BaseResponse(err error) (*types.BaseResp, error) {
	if err != nil {
		return &types.BaseResp{
			Code:    FailedCode,
			Message: FailedMessage,
		}, err
	}

	return &types.BaseResp{
		Code:    SuccessCode,
		Message: SuccessMessage,
	}, nil
}

func BaseResponseWithData(err error, data interface{}) (*types.BaseRespWithData, error) {
	if err != nil {
		return &types.BaseRespWithData{
			Code:    FailedCode,
			Message: FailedMessage,
			Data:    nil,
		}, err
	}

	return &types.BaseRespWithData{
		Code:    SuccessCode,
		Message: SuccessMessage,
		Data:    data,
	}, nil
}

func BaseResponseWithListData(err error, data interface{}, total int) (*types.BaseRespWithListData, error) {
	if err != nil {
		return &types.BaseRespWithListData{
			Code:    FailedCode,
			Message: FailedMessage,
			Data:    nil,
			Total:   0,
		}, err
	}

	return &types.BaseRespWithListData{
		Code:    SuccessCode,
		Message: SuccessMessage,
		Data:    data,
		Total:   total,
	}, nil
}

func HandlerSqlError(err error) error {
	if mysqlErr, ok := err.(*mysql.MySQLError); ok {
		switch mysqlErr.Number {
		case 1062:
			message := strings.TrimPrefix(mysqlErr.Message, "Duplicate entry ")
			tailIndex := strings.Index(message, " for")
			if tailIndex > 0 {
				runes := []rune(message)
				message = string(runes[0:tailIndex])
			}

			return NewErrorX(FailedCode, fmt.Sprintf("数据已存在: %s", message))
		// 为其他特定错误代码添加案例
		default:
			return err
		}
	} else {
		return err
	}
}
